package com.geovis.emergency.spd.biz.pc.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geovis.emergency.spd.biz.basic.service.IBasicPunchRuleService;
import com.geovis.emergency.spd.biz.pc.mapper.PcPunchMapper;
import com.geovis.emergency.spd.biz.pc.service.IPcDrillService;
import com.geovis.emergency.spd.biz.pc.service.IPcPunchRecordService;
import com.geovis.emergency.spd.biz.pc.service.IPcPunchService;
import com.geovis.emergency.spd.entity.basic.entity.BasicPunchRule;
import com.geovis.emergency.spd.entity.basic.entity.PcPunch;
import com.geovis.emergency.spd.entity.basic.entity.PcPunchRecord;
import com.geovis.emergency.spd.entity.mobile.pojo.vo.MobileLabelVO;
import com.geovis.emergency.spd.entity.mobile.pojo.vo.MobileSignInStatisticsVO;
import com.geovis.emergency.spd.entity.mobile.pojo.vo.MobileSignStatisticsByDaysVO;
import com.geovis.emergency.spd.entity.pc.entity.PcDrill;
import com.geovis.emergency.spd.entity.pc.entity.PcPlanOrgUser;
import com.geovis.emergency.spd.entity.pc.pojo.enums.PunchStatusEnum;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Array;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 应急预案指挥模块-打卡表 服务实现类
 * </p>
 *
 * @author lmolong
 * @since 2022-06-21
*/

@Service
@RequiredArgsConstructor
@Slf4j
public class PcPunchServiceImpl extends ServiceImpl<PcPunchMapper, PcPunch> implements IPcPunchService {

    private final IPcPunchRecordService pcPunchRecordService;

    private final IBasicPunchRuleService basicPunchRuleService;

    private final IPcDrillService pcDrillService;

    @Override
    public PcPunch selectUserPunch(String userId, String pcDrillId, Date date) {
        DateTime begin = DateUtil.beginOfDay(date);
        DateTime end =  DateUtil.endOfDay(date);
        return baseMapper.selectUserPunch(userId,pcDrillId,begin,end);
    }

    @Override
    public List<MobileSignInStatisticsVO> mobileStatistics(String userId, String pcDrillId, String date) {
        LocalDateTime startTime=LocalDateTimeUtil.parse(date+" 00:00:00","yyyy-MM-dd HH:mm:ss");
        LocalDateTime endTime=LocalDateTimeUtil.parse(date+" 23:59:59","yyyy-MM-dd HH:mm:ss");
        List<PcPunch> punches=this.list(Wrappers.lambdaQuery(PcPunch.class)
                .eq(PcPunch::getPcDrillId, pcDrillId)
                .gt(PcPunch::getPunchDate, startTime)
                .lt(PcPunch::getPunchDate, endTime)
                .eq(PcPunch::getPersonId,userId)
        .orderByDesc(PcPunch::getPunchDate));

        return buildStatData(punches,pcDrillId);
    }

    private List<MobileSignInStatisticsVO> buildStatData(List<PcPunch> punches,String pcDrillId)
    {
        List<MobileSignInStatisticsVO> result=new ArrayList<>();
        BasicPunchRule punchRule = basicPunchRuleService.getById("1");
        punches.stream().forEach(punch->{
            //签到
            if("1".equals(punch.getSignInStatus()))
            {
                List<PcPunchRecord> records=pcPunchRecordService.list(Wrappers.lambdaQuery(PcPunchRecord.class)
                        .eq(PcPunchRecord::getPcDrillId, pcDrillId)
                        .eq(PcPunchRecord::getType, "1")
                        .eq(PcPunchRecord::getPcPunchId, punch.getId())
                );
                List<MobileSignInStatisticsVO> statData=records.stream().map(record->buildStatData(record,punchRule,"1")).collect(Collectors.toList());
                result.addAll(statData);
            }
            //签退
            if("1".equals(punch.getSignOutStatus()))
            {
                List<PcPunchRecord> records=pcPunchRecordService.list(Wrappers.lambdaQuery(PcPunchRecord.class)
                        .eq(PcPunchRecord::getPcDrillId, pcDrillId)
                        .eq(PcPunchRecord::getType, "2")
                        .eq(PcPunchRecord::getPcPunchId, punch.getId())
                );
                List<MobileSignInStatisticsVO> statData=records.stream().map(record->buildStatData(record,punchRule,"2")).collect(Collectors.toList());
                result.addAll(statData);

            }
        });
        return result;
    }

    @Override
    public List<MobileSignStatisticsByDaysVO> mobileSignStatisticsByDaysVO(String userId, String pcDrillId, String startDate,String endDate) {
        PcDrill pcDrill=pcDrillService.getById(pcDrillId);


        LocalDateTime startTime=LocalDateTimeUtil.parse(startDate+" 00:00:00","yyyy-MM-dd HH:mm:ss");
        LocalDateTime endTime=LocalDateTimeUtil.parse(endDate+" 23:59:59","yyyy-MM-dd HH:mm:ss");
        List<PcPunch> punches=this.list(Wrappers.lambdaQuery(PcPunch.class)
                .eq(PcPunch::getPcDrillId, pcDrillId)
                .gt(PcPunch::getPunchDate, startTime)
                .lt(PcPunch::getPunchDate, endTime)
                .eq(PcPunch::getPersonId,userId));
        Long betweenDay = LocalDateTimeUtil.between(startTime,endTime, ChronoUnit.DAYS);
        List<MobileSignStatisticsByDaysVO> statistics=new ArrayList<>();
        LocalDate today=LocalDate.now();
        for(int x=0;x<betweenDay.intValue()+1;x++)
        {
            MobileSignStatisticsByDaysVO daysVO=new MobileSignStatisticsByDaysVO();
            LocalDateTime dateTime=startTime.plusDays(x);

            daysVO.setDate(dateTime.toLocalDate().toString());
            //如果是今天，则不统计，今天的考勤情况，要过了今天才能计算,且在演练启动之后的才开始计算考勤
            if(today.toString().equals(dateTime.toLocalDate().toString()) || dateTime.toLocalDate().isAfter(today) || dateTime.toLocalDate().isBefore(pcDrill.getStartTime().toLocalDate()))
            {
                continue;
            }
            Optional<PcPunch> userPunch=punches.stream().filter(p->p.getPunchDate().toLocalDate().toString().equals(dateTime.toLocalDate().toString())).findFirst();
            if(userPunch.isPresent())
            {
                PcPunch punch=userPunch.get();
                List<MobileSignInStatisticsVO> result=buildStatData(Arrays.asList(punch),pcDrillId);
                //目前一个人一天最多只会打2次卡
                if(result.size()<2)
                {
                    daysVO.setStatus(PunchStatusEnum.MISSING_CARD.getMsg());
                }
                if(result.size()==2)
                {
                    List<String> statusData=result.stream().map(MobileSignInStatisticsVO::getStatus).collect(Collectors.toList());
                    //正常
                    if(statusData.contains(PunchStatusEnum.SIGN_IN.getMsg()) && statusData.contains(PunchStatusEnum.SIGN_OUT.getMsg()))
                    {
                        daysVO.setStatus(PunchStatusEnum.NORMAL.getMsg());
                    }
                    //迟到
                    if(statusData.contains(PunchStatusEnum.BE_LATE.getMsg()))
                    {
                        daysVO.setStatus(PunchStatusEnum.BE_LATE.getMsg());
                    }
                    //早退
                    if(statusData.contains(PunchStatusEnum.LEAVE_EARLY.getMsg()))
                    {
                        daysVO.setStatus(PunchStatusEnum.LEAVE_EARLY.getMsg());
                    }

                }

            }
            else
            {
                daysVO.setStatus(PunchStatusEnum.MISSING_CARD.getMsg());
            }
            statistics.add(daysVO);
        }
        return statistics;
    }

    @Override
    public List<MobileLabelVO> statisticsTotal(String userId, String pcDrillId, String startDate, String endDate) {
        List<MobileSignStatisticsByDaysVO> statData=mobileSignStatisticsByDaysVO(userId,pcDrillId,startDate,endDate);
        long normal=statData.stream().filter(s->s.getStatus().equals("正常")).count();
        long abnormal=statData.size()-normal;
        MobileLabelVO normalVo = new MobileLabelVO();
        normalVo.setLabel("正常");
        normalVo.setValue(normal+"");
        MobileLabelVO abnormalVo = new MobileLabelVO();
        abnormalVo.setLabel("异常");
        abnormalVo.setValue(abnormal+"");

        return Arrays.asList(normalVo,abnormalVo);
    }


    private MobileSignInStatisticsVO buildStatData(PcPunchRecord record,BasicPunchRule punchRule,String type)
    {
        MobileSignInStatisticsVO statisticsVO=new MobileSignInStatisticsVO();
        statisticsVO.setId(record.getId());
        statisticsVO.setType(type);
        statisticsVO.setDate(LocalDateTimeUtil.format(record.getPunchTime(),"yyyy-MM-dd HH:mm:ss"));
        Date punchTime = Date.from(record.getPunchTime().atZone(ZoneId.systemDefault()).toInstant());
        if(type.equals("1"))
        {

            DateTime signInTime = DateUtil.parseTimeToday(punchRule.getSignInTime());
            if(punchTime.after(signInTime)){
                statisticsVO.setStatus(PunchStatusEnum.BE_LATE.getMsg());
            }else{
                statisticsVO.setStatus(PunchStatusEnum.SIGN_IN.getMsg());
            }
        }
        else
        {
            DateTime signOutTime = DateUtil.parseTimeToday(punchRule.getSignOutTime());
            if (punchTime.before(signOutTime)) {
                statisticsVO.setStatus(PunchStatusEnum.LEAVE_EARLY.getMsg());
            } else {
                statisticsVO.setStatus(PunchStatusEnum.SIGN_OUT.getMsg());
            }
        }
        return statisticsVO;
    }

    @Override
    public Integer selectCountByPcDrillIdAndDate(String pcDrillId, String date, String userId,String status) {
        Date dateTime =  DateUtil.parseDate(date);
        return baseMapper.selectCountByPcDrillIdAndDate(pcDrillId,userId,DateUtil.beginOfMonth(dateTime),DateUtil.endOfMonth(dateTime),status);
    }
}
